import Api from '../request/api.js';
import fs from 'fs';
import { sleep, log } from '../utils/utils.js';
import process from 'process';
import dotenv from 'dotenv';
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import { Page, Browser } from 'puppeteer-core';
import dayjs from 'dayjs';
import axios from 'axios';
import { PayType, TicketChannel } from '../constant/index.js';

const ua =
  'Mozilla/5.0 (Linux; Android 13; 22011211C Build/TP1A.220624.014; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.72 MQQBrowser/6.2 TBS/046247 Mobile Safari/537.36 AppVersion/4.1.6';

// const waitSelectTime = 300000; // 选座等待时间
dotenv.config();
puppeteer.use(StealthPlugin());
const {
  EXECUTABLE_PATH,
  CINEMA_ACC_ID,
  CINEMA_TOKEN,
  CINEMA_ACCOUNT,
  CINEMA_DATA,
  CINEMA_PWD,
  CINEMA_CHANNEL,
  ENV,
} = process.env;

const API = new Api();

export default class Happiness {
  /**
   * @type  {Page} page
   */
  page;

  /**
   * @type  {Browser} browser
   */
  browser;

  // token
  loginToken = CINEMA_TOKEN;

  // 接口请求头
  requestHeader = {
    'User-Agent': ua,
    Accept: 'application/json',
    'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
    'Content-Type': 'application/x-www-form-urlencoded',
    'gray-lease-code': 'GS',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    Pragma: 'no-cache',
    'Cache-Control': 'no-cache',
  };

  // 订单信息
  order = {
    state: '',
    ticketCode: '',
    paramDetail: {}, // 订单详情参数
  };

  // 锁定订单ID
  lockOrderId = '';

  // data
  dataJson = null;

  getPage() {
    return this.page;
  }

  getBrowser() {
    return this.browser;
  }

  // 写入本地保存
  setOrderState(state, ticketCode = '', paramDetail = {}) {
    if (ticketCode) {
      this.order.ticketCode = ticketCode;
    }
    this.order.paramDetail = { ...this.order.paramDetail, ...paramDetail };
    this.order.state = state;

    fs.writeFileSync(
      './orderJson/' + this.dataJson.sn + '.json',
      JSON.stringify(this.order, null, 2),
      {
        flag: 'w',
      },
      (err) => {
        if (err) {
          console.error('订单状态写入', err);
        }
      }
    );
  }

  // 订单开始 初始化
  async orderStart(dataJson) {
    // 检查登录
    await this.checkLogin({
      cinemaAccId: CINEMA_ACC_ID,
      cinemaAccount: CINEMA_ACCOUNT,
      cinemaAccountPwd: CINEMA_PWD,
    });

    this.order = {
      state: '',
      ticketCode: '',
      paramDetail: {},
    };
    this.dataJson = dataJson;
    this.lockOrderId = '';
  }

  async init() {
    // 初始化
    this.browser = await puppeteer.launch({
      executablePath: EXECUTABLE_PATH,
      //设置超时时间
      timeout: 15000,
      ignoreHTTPSErrors: true,
      //   devtools: true,
      headless: true,
      devtools: ENV === 'local',
      //   headless: ENV === 'local' ? false : 'new',
      args: [
        // '--disable-gpu',
        // '--disable-setuid-sandbox',
        // '--no-first-run',
        // '--no-zygote',
        // '--single-process',
        '--disable-dev-shm-usage',
        '--no-sandbox',
        '--disable-plugins',
      ],
    });
    // this.page = await this.browser.newPage();
    const pages = await this.browser.pages();
    this.page = pages[0];
    await this.page.setGeolocation({ latitude: 31.23, longitude: 121.47 });
    await this.page.setUserAgent(ua); // 设置UA
    await this.page.setViewport({ width: 375, height: 630 });
  }

  // 登录
  async login(loginToken = this.loginToken) {
    await this.page.goto(
      `https://app.omnijoi.cn/v4.0/index.php?r=film%2Fcinemaview&cinemaNo=${CINEMA_DATA.linkid}`,
      {
        waitUntil: 'domcontentloaded',
      }
    );
    // 打开首页 document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";

    await this.page.evaluate((val) => {
      val.split('; ').forEach((item) => {
        document.cookie =
          item + '; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/';
      });
    }, loginToken);
  }

  // 登录
  async checkLogin(user) {
    // 确认登录态是否生效
    const resData = await this.requestPageApi('usermenu%2Forderstatusnum');
    if (!resData || resData.status != 1) {
      log('登录态失效 登录用户:' + user.cinemaAccount, 'error');
      // 退出程序 人工处理
      await API.authExpire(user.cinemaAccId);
      if (CINEMA_CHANNEL == TicketChannel.TASK) {
        return false;
      }
      await this.browser.close();
      process.exit(0);
    }
    return true;
  }

  // 获取座位信息
  async getSeat() {
    // 等待选座
    const dataJson = this.dataJson;
    const { scheduleKey } = dataJson.showObj;
    await this.page.goto(`https://app.omnijoi.cn/${scheduleKey}`, {
      waitUntil: 'domcontentloaded',
    });

    // 获取数据
    const seatData = await this.page.evaluate(() => window.option);
    if (!seatData.rowsData || seatData.rowsData.length <= 0) {
      log('场次数据获取失败 ' + JSON.stringify(seatData), 'error');
      throw new Error('场次选择失败[RETRY]');
    }

    // 订单座位
    const seatListArr = dataJson.seatList.map((i) =>
      i.match(/[\d|A-Za-z]+/g).map((d) => (isNaN(Number(d)) ? d : String(d)))
    );
    const rows = seatListArr.map((s) => s[0]);
    const cols = seatListArr.map((s) => s[1]);
    // 获取座位
    const seatList = [];
    const seats = seatData.rowsData;
    for (const seat of seats) {
      if (!rows.includes(seat.rowName)) {
        continue;
      }
      for (const col of seat.columns) {
        if (!cols.includes(col.colName)) {
          continue;
        }

        // 防止多排串联
        if (
          !seatListArr.some(
            (arr) => arr[0] === seat.rowName && arr[1] === col.colName
          )
        ) {
          continue;
        }

        if (col.status !== 0) {
          throw new Error(
            `座位已被锁定 ${this.dataJson.from} ${this.dataJson.cinemaName}`
          );
        }

        seatList.push({
          cinemaPrice: seatData.CinemaPrice,
          sectionNo: seatData.sectionNo,
          row: seat.rowNo,
          col: col.colNo,
        });
      }
    }
    if (seatList.length < dataJson.seatList.length) {
      throw new Error('座位未找到');
    }
    return seatList;
  }

  // 锁定座位
  /**
   * [{"areaId":"0","column":3,"columnName":"2","flag":0,"name":"1排2座","row":1,"rowName":"1","seatId":"000000031026-1-3","status":1}]
   */
  async lockSeat(seatList) {
    // 座位锁定请求
    const lockBizData = await this.requestPageApi(
      'film%2Forder&cinemaNo=' + CINEMA_DATA.linkid,
      {
        sendType: 1,
        orderType: 1,
        cardActId: '',
        showNo: this.dataJson.showObj.showNo,
        goods: '',
        seats: seatList
          .map((seat) => `${seat.sectionNo}|${seat.row}|${seat.col}`)
          .join(','),
        CinemaPrice: seatList[0].cinemaPrice,
        cardType: '',
        isBack: 1,
        isChange: 1,
      },
      'POST'
    );
    if (lockBizData && lockBizData.status === 1) {
      // 成功锁座
      log('座位锁定成功');
      const payUrl = lockBizData.data;
      this.lockOrderId = /orderNo=(.+?)&/.exec(payUrl)[1];

      const seatData = await this.page.evaluate(() => window.option);
      // 添加上会员卡使用信息
      if (seatData.urlParams) {
        return (
          payUrl +
          `&userCardActPrice=${seatData.urlParams.userCardActPrice}&title=确认订单_pay/payorder&style=0&_target=target`
        );
      } else {
        return payUrl;
      }
    } else {
      // 锁座失败
      log('座位锁定请求失败 ' + JSON.stringify(lockBizData), 'error');
      throw new Error('锁座失败[TRY]:' + (lockBizData.msg || '未知'));
    }
  }

  // 获取订单信息
  async submitOrderInfo(cinemaInfo, payLink) {
    // 跳转到支付页
    await this.page.goto(`https://app.omnijoi.cn${payLink}`, {
      waitUntil: 'networkidle0',
    });
    // await sleep(5000);

    // 获取支付信息
    const payData = await this.page.evaluate(() => window.option);
    if (!payData || !payData.payOrderUseDataPackage) {
      throw new Error('支付信息获取失败[RETRY]');
    }

    // 支付方式
    let payType;
    let costFee = 999999;
    if (cinemaInfo.settle_type == PayType.BALANCE) {
      ({ payType, costFee } = this.getVipCost(payData, cinemaInfo));
    } else if (cinemaInfo.settle_type == PayType.COUPON) {
      ({ payType, costFee } = this.getCouponCost(cinemaInfo));
    } else if (cinemaInfo.settle_type == PayType.E_TICKET) {
      ({ payType, costFee } = this.getETicketCost(cinemaInfo));
    } else {
      // 根据成本 选择支付方式
      if (cinemaInfo.vip_cost_ratio > 0) {
        // VIP
        ({ payType, costFee } = this.getVipCost(payData, cinemaInfo));
        log('海洋卡会员成本:' + costFee);
      }
      if (cinemaInfo.coupon_fee > 0) {
        // 抵扣券
        const { payType: pt, costFee: vipCostFee } =
          this.getCouponCost(cinemaInfo);
        if (vipCostFee < costFee) {
          costFee = vipCostFee;
          payType = pt;
        }
      }
      if (cinemaInfo.e_ticket_fee > 0) {
        // 电子券
        const { payType: pt, costFee: eTicketCostFee } =
          this.getETicketCost(cinemaInfo);
        if (eTicketCostFee < costFee) {
          costFee = eTicketCostFee;
          payType = pt;
        }
      }
    }

    // 更新成本
    await API.updateOrderCost(this.dataJson.id, costFee);
    const sellAmount = Number(this.dataJson.sellAmount);
    // force_ticket是否强制出票
    if (sellAmount > 0 && sellAmount <= costFee && !cinemaInfo.force_ticket) {
      throw new Error(
        `成本高于报价[类型${payType}-成本${costFee}-报价${sellAmount}]`
      );
    }
    // 开始进行支付
    let payResult = false;
    if (payType === PayType.BALANCE) {
      // 使用海洋会员卡余额
      payResult = await this.useVipBalance(payData, cinemaInfo, costFee);
    } else if (payType === PayType.COUPON) {
      // 使用抵扣券
      payResult = await this.useCoupon();
    } else if (payType === PayType.E_TICKET) {
      // 使用抵扣券
      payResult = await this.useETicket();
    }
    if (!payResult) {
      throw new Error('支付失败-类型' + payType);
    }
    // 设置订单状态
    this.setOrderState('success', '', {
      costFee,
      payType,
      orderId: this.lockOrderId,
    });

    // 从订单列表里获取订单信息
    return this.getOrderInfo();
  }

  // VIP成本
  getVipCost(payData, cinemaInfo) {
    // VIP
    const ticketCounts = payData.ticketCounts;
    const vipCardData = JSON.parse(payData.payOrderUseDataPackage);
    const { virtualCardInfo } = vipCardData;
    return {
      payType: PayType.BALANCE,
      costFee:
        (virtualCardInfo.userCardPrice * ticketCounts ||
          virtualCardInfo.cardPayment) * cinemaInfo.vip_cost_ratio || 999999,
    };
  }

  // 抵扣券成本
  getCouponCost(cinemaInfo) {
    // 抵扣券
    const ticketCount = this.dataJson.seatList.length;
    const { isSpec, weight, couponPlus = 0 } = this.dataJson.showObj;
    let costFee = cinemaInfo.coupon_fee * ticketCount;
    if (isSpec) {
      costFee = cinemaInfo.coupon_fee * weight * ticketCount + couponPlus;
    }
    return {
      payType: PayType.COUPON,
      costFee,
    };
  }

  // 电子券成本
  getETicketCost(cinemaInfo) {
    // 抵扣券
    const ticketCount = this.dataJson.seatList.length;
    const { isSpec, weight } = this.dataJson.showObj;
    return {
      payType: PayType.E_TICKET,
      costFee: isSpec
        ? cinemaInfo.e_ticket_fee * weight * ticketCount
        : cinemaInfo.e_ticket_fee * ticketCount,
    };
  }

  // 获取订单原始金额
  getOriginPrice(privilegeBizData) {
    return privilegeBizData.privileges.find(
      (p) => p.privilegeType === 'ORIGINAL_PRICE'
    )['privilegeTotalPrice'];
  }

  // 处理data
  handleCoupon(couponList, type = 1) {
    return couponList.map((coupon) => ({
      type,
      couponNo: coupon.verCode,
      status: coupon.couponStatus === '4' ? 1 : 2,
      timeStart: new Date(coupon.startDate).getTime() / 1000,
      timeEnd: new Date(coupon.endDate + ' 23:59:59').getTime() / 1000,
      couponVer: coupon.policyId || '',
      couponName: coupon.couponsName || '',
      couponInfo: coupon.policyName || '',
    }));
  }

  // 使用抵扣券
  async useCoupon() {
    // 获取优惠券列表URL
    const couponListUrl = await this.page.$eval(
      '#m_payType .list li[data-type="6"]',
      (ele) => ele.getAttribute('data-url')
    );
    await this.page.goto(`https://app.omnijoi.cn${couponListUrl}`);

    // 获取数据
    const couponListData = await this.page.evaluate(() => window.option);
    if (!couponListData) {
      throw new Error('兑换券数据获取失败[RETRY]');
    }
    // 更新券数
    let useCouponNum = this.dataJson.seatList.length;
    const { isSpec, weight } = this.dataJson.showObj;
    if (isSpec) {
      // 特殊影厅
      useCouponNum = useCouponNum * weight;
    }
    if (couponListData.totalCount < useCouponNum) {
      throw new Error(
        `兑换券数量不足[${couponListData.totalCount}-${useCouponNum}]`
      );
    }
    // 查找使用优惠券
    const ticketInfos = [];
    for (const couponInfo of couponListData.records) {
      if (useCouponNum <= 0) {
        break;
      }
      if (couponInfo.couponStatus !== '4') {
        continue;
      }
      ticketInfos.push(couponInfo);
      useCouponNum = useCouponNum - 1;
    }

    // 验证优惠券
    const vercodes = ticketInfos.map((t) => t.verCode);
    const validatorData = await this.requestPageApi(
      'usercoupon%2Fvalidator&orderNo=' + this.lockOrderId,
      {
        tickets: vercodes.join(','),
      },
      'POST'
    );
    if (!validatorData || validatorData.status !== 1) {
      log('兑换券验证失败 ' + JSON.stringify(validatorData));
      throw new Error('兑换券验证失败');
    }
    if (validatorData.data.spreadPrice > 0) {
      throw new Error(
        '兑换券需要额外支付金额:' + validatorData.data.spreadPrice
      );
    }

    // 执行兑换
    const exchangeData = await this.requestPageApi(
      `usercoupon/pay-exchange&orderNo=${this.lockOrderId}&title=loading...&style=0&_target=target`,
      {
        tickets: vercodes.join(','),
      },
      'POST'
    );
    if (!exchangeData || exchangeData.status !== 1) {
      log('兑换券兑换失败 ' + JSON.stringify(exchangeData));
      throw new Error('兑换券兑换失败[RETRY]');
    }

    // 上传券
    const couponList = this.handleCoupon(
      couponListData.records.filter((i) => !vercodes.includes(i.verCode))
    ); // 更新券列表
    await API.uploadCoupon(
      couponList,
      CINEMA_ACC_ID,
      CINEMA_ACCOUNT,
      TicketChannel.HAPPINESS
    );

    await API.updateCouponNum(couponListData.totalCount - useCouponNum);

    return true;
  }

  // 使用电子券
  async useETicket() {
    // 获取优惠券列表URL
    const eTicketListUrl = await this.page.$eval(
      '#m_payType .list li[data-type="4"]',
      (ele) => ele.getAttribute('data-url')
    );
    await this.page.goto(`https://app.omnijoi.cn${eTicketListUrl}`);
    // 获取数据
    const eTicketListData = await this.page
      .$$eval('#m_eleTicketList .m-ticket', (eles) =>
        eles
          .filter((el) =>
            el.querySelector('.channel').innerHTML.includes('不限')
          )
          .map((ele) => {
            // "2023-08-04至2024-12-31"
            let validDate;
            if (!ele.querySelector('.valid')) {
              validDate = ['2023-09-10', '2044-09-10'];
            } else {
              validDate = ele.querySelector('.valid').innerHTML.split('至');
            }
            return {
              type: 2,
              couponNo: ele.getAttribute('data-couponno'),
              status: 1,
              timeStart: new Date(validDate[0]).getTime() / 1000,
              timeEnd: new Date(validDate[1] + ' 23:59:59').getTime() / 1000,
              couponVer: ele.getAttribute('data-source') || '',
              couponName: '电子券',
              couponInfo:
                (ele.querySelector('.olor-blue') || {}).innerHTML || '',
            };
          })
      )
      .catch((e) => {
        return null;
      });

    if (!eTicketListData) {
      await sleep(100000);
      throw new Error('电子券查询异常');
    }

    log('电子券整理数据: ' + JSON.stringify(eTicketListData));

    let useNum = this.dataJson.seatList.length;
    const { isSpec, weight } = this.dataJson.showObj;
    if (isSpec) {
      // 特殊影厅
      useNum = useNum * weight;
    }
    if (eTicketListData.length < useNum) {
      throw new Error('电子券数量不足');
    }
    // 查找使用优惠券
    const ticketsArr = [];
    for (const eTicketInfo of eTicketListData) {
      if (useNum <= 0) {
        break;
      }
      ticketsArr.push(eTicketInfo.couponNo);
      useNum = useNum - 1;
    }

    // 验证优惠券
    const validatorData = await this.requestPageApi(
      'userwallet%2Fvalidatorcouponticket',
      {
        orderNo: this.lockOrderId,
        tickets: ticketsArr.join(','),
      },
      'POST'
    );
    if (!validatorData || validatorData.status !== 1) {
      log('电子券验证失败 ' + JSON.stringify(validatorData));
      throw new Error('电子券验证失败[RETRY]');
    }
    if (validatorData.data.spreadPrice > 0) {
      throw new Error(
        '电子券需要额外支付金额:' + validatorData.data.spreadPrice
      );
    }

    // 执行兑换
    const exchangeData = await this.requestPageApi(
      'pay%2Fcreatecouponticketpay',
      {
        orderNo: this.lockOrderId,
        tickets: ticketsArr.join(','),
      },
      'POST'
    );
    if (!exchangeData || exchangeData.status !== 1) {
      log('电子券兑换失败 ' + JSON.stringify(exchangeData));
      throw new Error('电子券兑换失败[RETRY]');
    }

    // 上传券
    await API.uploadCoupon(
      eTicketListData.filter((i) => !ticketsArr.includes(i.couponNo)),
      CINEMA_ACC_ID,
      CINEMA_ACCOUNT,
      TicketChannel.HAPPINESS
    );
    // 更新券数
    await API.updateETicketNum(eTicketListData.length - useNum);
    return true;
  }

  // 使用VIP余额
  async useVipBalance(payData, cinemaInfo, costFee) {
    const { cardListApi, cardPayApi, oldCardPayApi } = payData;
    const { thirdPayInfo } = JSON.parse(payData.payOrderUseDataPackage);
    const matchR = oldCardPayApi.match(/cardActId=(.*?)&/);
    let url = cardListApi;
    if (matchR) {
      url += `&cardActId=${matchR[1]}&cinemaNo=${cinemaInfo.cinema_data.linkid}`;
    }

    // 卡列表信息
    const vipCardInfo = await this.requestPageApi(
      url.replace('/v4.0/index.php?r=', '')
    );
    if (!vipCardInfo || vipCardInfo.status != 1) {
      throw new Error('获取海洋会员卡列表失败[RETRY]');
    }
    const cardInfo = vipCardInfo.data.cards[0]; // 取第一个
    if (!cardInfo || cardInfo.cardStatus !== '4') {
      throw new Error('海洋会员卡状态异常[TRY]');
    }

    // 会员卡耗尽
    if (
      Math.round(cardInfo.price * cinemaInfo.vip_cost_ratio) !=
      Math.round(costFee)
    ) {
      //   log(
      //     '会员卡耗尽 ' +
      //       JSON.stringify({
      //         url: url.replace('/v4.0/index.php?r=', ''),
      //         vip_cost_ratio: cinemaInfo.vip_cost_ratio,
      //         costFee,
      //         vipCardInfo,
      //       })
      //   );
      throw new Error('会员卡价格变动:' + cardInfo.price);
    }
    // if (
    //   cardInfo.addParams &&
    //   (cardInfo.addParams.realAllPrice === '0' ||
    //     cardInfo.addParams.realSinglePrice.includes('|'))
    // ) {
    //   throw new Error('会员卡购买数量超出限制');
    // }

    if (Number(cardInfo.cardBalance) < Number(cardInfo.price)) {
      throw new Error('海洋会员卡余额不足');
    }

    // 出票
    //orderNo=XF100112702764&payment=180.00&sendType=0&cardNo=Z9999211005610&cardLevel=海洋会员卡政策&cardPwd=111111&realAllPrice=120.00&realSinglePrice=60.00|60.00&discountFlag=0|0&discountName=会员价|会员价&changePrice=&memberPrice=60.00|60.00&_csrf=WGd6WVNwdHYPPTYrBSIWRBchV3QqA0cROiUsLRIvFwwzCiAqFhtCPQ==
    const orderInfo = await this.requestPageApi(
      cardPayApi.replace('/v4.0/index.php?r=', ''),
      {
        orderNo: this.lockOrderId,
        payment: thirdPayInfo.payment,
        sendType: 0,
        cardPwd: cinemaInfo.vip_pwd,
        ...cardInfo.addParams,
      },
      'POST'
    );
    if (!orderInfo || orderInfo.status !== 1) {
      log('海洋会员卡支付失败：' + JSON.stringify(orderInfo));
      throw new Error('海洋会员卡支付失败：' + (orderInfo.msg || ''));
    }
    // 更新余额
    await API.updateVipBalance(
      (cardInfo.cardBalance - cardInfo.price).toFixed(2),
      cardInfo.addParams.cardNo || 'unkown',
      '海洋会员卡'
    ).catch((e) => {
      log('更新会员卡余额失败：' + JSON.stringify(e));
    });
    return true;
  }

  // 获取订单信息
  async getOrderInfo() {
    const filePath = './orderJson/' + this.dataJson.sn + '.json';
    if (!fs.existsSync(filePath)) {
      return false;
    }
    const buffer = fs.readFileSync(filePath);
    const fileContent = buffer.toString();
    if (!fileContent) {
      return false;
    }
    const orderState = JSON.parse(fileContent);
    this.order = orderState;
    await this.page.goto(
      `https://app.omnijoi.cn/v4.0/index.php?r=order/order&title=全部订单_order/order&style=2_编辑&_target=target`,
      {
        waitUntil: 'domcontentloaded',
      }
    );
    const orderUrlList = await this.page.$$eval(
      '#my_order .yp div[data-url]',
      (eles) => eles.map((ele) => ele.getAttribute('data-url'))
    );
    // 订单详情URL
    const orderUrl = orderUrlList.find((u) =>
      u.includes(orderState.paramDetail.orderId)
    );
    if (!orderUrl) {
      throw new Error('获取订单详情链接失败[RETRY]');
    }

    let uploadLink = '';
    if (this.dataJson.screenshot) {
      await this.page.goto(`https://app.omnijoi.cn${orderUrl}`);
      // 截图
      await this.page.setViewport({
        width: 375,
        height: 500,
      });
      await sleep(100);
      const screenshotPath = './screenshot/' + this.dataJson.sn + '.png';
      await this.page.screenshot({
        path: screenshotPath,
      });

      // 上传截图
      uploadLink = await API.uploadScreenshot(screenshotPath);
    }

    const orderInfoStr = orderUrl
      .split('&')
      .find((i) => i.includes('info='))
      .replace('info=', '');
    const orderInfo = JSON.parse(
      decodeURIComponent(decodeURIComponent(orderInfoStr))
    );
    const ticketCode = orderInfo.ticketNo.split(',').join('|');
    this.setOrderState('success', ticketCode);

    return {
      orderId: orderInfo.orderNo,
      payType: orderState.paramDetail.payType,
      ticketCode,
      uploadLink,
    };
  }

  // 解锁座位
  async unlockSeat() {
    //https://app.omnijoi.cn/v4.0/index.php?r=order%2Funpaid
    await this.page.goto(
      'https://app.omnijoi.cn/v4.0/index.php?r=order%2Funpaid',
      {
        waitUntil: 'domcontentloaded',
      }
    );

    if (this.lockOrderId) {
      // 解锁请求
      return await this.requestPageApi(
        'film%2Fcancelorder',
        {
          orderNo: this.lockOrderId,
          orderType: '',
        },
        'POST'
      );
    }
    return true;
  }

  // 页面接口请求
  async requestPageApi(path, data, method = 'GET', first = true) {
    const url = `https://app.omnijoi.cn/v4.0/index.php?r=${path}`;
    let postData = null;
    if (data) {
      if (method.toLocaleUpperCase() === 'POST') {
        const cfToken = await this.page.$eval(
          'meta[name="csrf-token"]',
          (element) => {
            return element.getAttribute('content');
          }
        );
        data._csrf = cfToken;
      }
      postData = Object.keys(data)
        .map((k) => `${k}=${data[k]}`)
        .join('&');
    }
    const res = await this.page.evaluate(
      (url, requestHeader, data, method) => {
        const fetchConf = {
          method,
          credentials: 'include',
          mode: 'cors',
          headers: requestHeader,
        };
        if (method.toLocaleUpperCase() === 'POST') {
          fetchConf.body = data;
        }
        return fetch(url, fetchConf)
          .then((res) => res.json())
          .catch((e) => console.error(e));
      },
      url,
      { ...this.requestHeader, referrer: this.page.url() },
      postData,
      method
    );
    if (!res || res.status != 1) {
      log(
        '幸福请求异常 ' +
          JSON.stringify({
            url,
            header: { ...this.requestHeader, referrer: this.page.url() },
            postData,
            method,
          }) +
          ' ' +
          JSON.stringify(res),
        'error'
      );
    }
    return res;
  }

  // 订单回退
  async orderRollback(dataJson) {
    log('回调订单状态,出票失败');
    // 订单锁定取消
    await API.orderRollback(dataJson.id, dataJson.msg).catch((e) =>
      console.error('取消订单请求异常', e)
    );
    if (!this.order.state) {
      if (this.lockOrderId) {
        // 仅仅是座位锁定成功 订单取消锁定
        const unlockRes = await this.unlockSeat();
        log(`解锁座位:${this.lockOrderId} ${JSON.stringify(unlockRes)}`);
      }
    }

    return true;
  }

  // 更新账户场次信息
  async updateShow(task) {
    // cinema_data: {"wapid": "XINGFU", "cinema": {"id": "", "name": "幸福蓝海（江宁店）", "linkid": "M100010023", "address": "南京市江宁区东山街道金箔路518号", "shortName": "", "permission": ""}, "linkid": "M100010023", "location": {"id": "320100", "name": "南京市"}}
    const referrerUrl = `https://app.omnijoi.cn/v4.0/index.php?r=film/movie&cinemaNo=${
      task.cinema_data.linkid
    }&showDate=${dayjs().format(
      'MMDD'
    )}&showIndex=1&title=loading..._film%2Fmovie&style=0&_target=target`;
    const requestConfig = {
      headers: {
        'User-Agent': ua,
        Referer: referrerUrl,
      },
    };
    await this.page.goto(referrerUrl, {
      timeout: 5 * 1000,
      waitUntil: 'networkidle0',
    });

    const eles = await this.page.$$eval('#m_hotFilms li', (eles) =>
      eles.map((ele) => ({
        filmId: ele.getAttribute('data-filmno'),
        filmName: ele.getAttribute('data-cname'),
      }))
    );
    const filmMap = {};
    for (const el of eles) {
      const { filmId, filmName } = el;
      const weekList = await axios
        .get(
          `https://app.omnijoi.cn/v4.0/index.php?r=film%2Fschedule&cinemaNo=${task.cinema_data.linkid}&filmNo=${filmId}&`,
          requestConfig
        )
        .then((res) => res.data.data && res.data.data.weekList);
      if (!weekList || !Array.isArray(weekList)) {
        continue;
      }

      if (!filmMap[filmName]) {
        filmMap[filmName] = [];
      }
      for (const l of weekList) {
        const date = `${dayjs().format('YYYY')}-${l.showDate
          .replace('日', '')
          .replace('月', '-')}`;
        for (const schedule of l.shows) {
          const showTime = `${date} ${schedule.showTime}:00`;
          filmMap[filmName].push({
            showTime,
            isSpec: ['IMAX', '4D', 'VIP'].some((w) =>
              schedule.hallName.includes(w)
            ),
            hallId: schedule.hallNo,
            scheduleKey: schedule.seatUrl,
            showNo: schedule.showNo,
            hallName: schedule.hallName,
            displayPrice: Math.round(
              schedule.virtualUserPrice * task['vip_cost_ratio'] * 100
            ), // 会员卡价格*系数
            originalStandardPrice: schedule.show_price * 100, // 标准价格
            standardPrice: schedule.CinemaPrice * 100, // 展示原价
            lowestPrice: schedule.surplusPercent * 100, // 发行价
            ticketFee: 0, // 影院手续费
          });
        }
      }
    }
    await API.updateShowlist(
      task.cinema_id,
      task.account_id,
      task.vip_price_status,
      filmMap
    );

    log(
      `${task['cinema_name']}[${task['cinemas_code']}] 场次数据更新成功[${task.account}]`
    );
  }

  // 更新院线
  async updateCinemas(taskData) {
    const referrerUrl = 'https://m.omnijoi.cn/index.aspx';
    const requestConfig = {
      headers: {
        'User-Agent': ua,
        Referer: referrerUrl,
      },
    };
    const allCitys = await axios
      .get(
        'https://m.omnijoi.cn/Infrastructure/GetPostData.ashx?action=getAllOpenCity',
        requestConfig
      )
      .then((res) => res.data);
    const cityCinemasMap = [];
    for (const area of allCitys) {
      for (const city of area.List) {
        await sleep(100);
        const cinemas = await axios
          .get(
            `https://m.omnijoi.cn/Infrastructure/GetPostData.ashx?action=getCinemaList&cityNo=${
              city.AreaNo
            }&cityName=${escape(city.AreaName)}&rand=${Math.random()}`,
            requestConfig
          )
          .then((res) => res.data);

        if (!cinemas || !Array.isArray(cinemas)) {
          continue;
        }

        cinemas.forEach((ele) => {
          cityCinemasMap.push({
            address: ele.address,
            cityCode: city.AreaNo,
            cityName: city.AreaName,
            cinemaName: ele.cinemaName,
            cinemaLinkId: ele.cinemaNo,
          });
        });
      }
    }

    await API.updateCinemasData(
      taskData.id,
      taskData.vip_price_status,
      cityCinemasMap
    );

    log(
      `${taskData['cinemas_name']}[${taskData['cinemas_code']}] 院线数据更新成功`
    );
  }
}
